package com.heima.comment.service.impl;

import com.heima.aliyun.scan.GreenScan;
import com.heima.aliyun.scan.ScanResult;
import com.heima.comment.service.CommentHotService;
import com.heima.comment.service.CommentService;
import com.heima.common.exception.CustException;
import com.heima.feigns.UserFeign;
import com.heima.model.comment.dtos.CommentDTO;
import com.heima.model.comment.dtos.CommentLikeDTO;
import com.heima.model.comment.dtos.CommentSaveDTO;
import com.heima.model.comment.pojos.ApComment;
import com.heima.model.comment.pojos.ApCommentLike;
import com.heima.model.comment.vos.ApCommentVo;
import com.heima.model.common.dtos.ResponseResult;
import com.heima.model.common.enums.AppHttpCodeEnum;
import com.heima.model.threadlocal.AppThreadLocalUtils;
import com.heima.model.user.pojos.ApUser;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @Program: day57-leadnews
 * @Description:
 * @Data: 2022/8/5 23:12
 **/
@Service
@Slf4j
public class CommentServiceImpl implements CommentService {

    @Autowired
    UserFeign userFeign;

    @Autowired
    GreenScan greenScan;

    @Autowired
    MongoTemplate mongoTemplate;

    @Autowired
    CommentHotService commentHotService;

    @Autowired
    RedissonClient redisson;

    /**
     * 保存评论
     * @param dto
     * @return
     */
    @Override
    public ResponseResult saveComment(CommentSaveDTO dto) {
        // 1. 校验参数
        // 校验是否登录
        Integer userId = AppThreadLocalUtils.getUser().getId();
        if (userId == null){
            CustException.cust(AppHttpCodeEnum.NEED_LOGIN);
        }
        // 校验文章id   校验内容不为空  校验内容长度不能大于140个字符 (validated校验)
        // 2. 阿里云校验评论内容是否违规
        // 过滤掉违规词汇：替换为**
        String needContent = null;
        try {
            ScanResult scanResult = greenScan.greenTextScan(dto.getContent());
            // 过滤后的字符串
             needContent = scanResult.getFilteredContent();
           // dto.setContent(content);
        } catch (Exception e) {
            e.printStackTrace();
            log.error("阿里云文本审核异常！");
        }
        // 3. 远程查询当前登陆用户信息
        ResponseResult<ApUser> user = userFeign.findUserById(userId);
        ApUser apUser = user.getData();
        // 4. 创建评论信息，并保存到mongo
        ApComment apComment = new ApComment();
        apComment.setAuthorId(userId);
        apComment.setAuthorName(apUser.getName());
        apComment.setArticleId(dto.getArticleId());
        apComment.setType((short) 0);
        if (needContent == null) {
            needContent = dto.getContent();
        }
        apComment.setContent(needContent);
        apComment.setLikes(0);
        apComment.setReply(0);
        apComment.setFlag((short) 0);
        apComment.setCreatedTime(new Date());
        apComment.setUpdatedTime(new Date());
        mongoTemplate.save(apComment);
        return ResponseResult.okResult(apComment);
    }

    /**
     * 点赞评论
     * @param dto
     * @return
     */
    @Override
    public ResponseResult likeComment(CommentLikeDTO dto) {
        // 1. 参数校验
        ApUser user = AppThreadLocalUtils.getUser();
        if (user == null){
            CustException.cust(AppHttpCodeEnum.NEED_LOGIN);
        }
        // 评论id不能为空  operation必须为 0  或  1

        // 加锁
        RLock lock = redisson.getLock("likes-Lock");
        lock.lock();
        ApComment apComment;

        try {
            // 2. 根据评论id查询评论数据， 为null返回错误信息
            Query apCommentQuery = Query.query(Criteria.where("id").is(dto.getCommentId()));
            apComment = mongoTemplate.findOne(apCommentQuery, ApComment.class);
            if (apComment == null){
                CustException.cust(AppHttpCodeEnum.DATA_NOT_EXIST);
            }
            // 判断操作：0：点赞    1：取消点赞
            int operation = dto.getOperation().intValue();
            // 3. 如果是点赞操作 判断是否已经点赞
            Query apCommentLikeQuery = Query.query(Criteria.where("authorId").is(user.getId()).and("commentId").is(dto.getCommentId()));
            ApCommentLike commentLike = mongoTemplate.findOne(apCommentLikeQuery, ApCommentLike.class);
            // 点赞操作
            if (operation == 0){
                // 点过赞提示 请勿重复点赞
                if (commentLike != null){
                    CustException.cust(AppHttpCodeEnum.DATA_NOT_ALLOW,"请勿重复点赞");
                }
                // 未点过赞   保存点赞信息到mongo
                ApCommentLike apCommentLike = new ApCommentLike();
                apCommentLike.setCommentId(apComment.getId());
                apCommentLike.setAuthorId(user.getId());
                apCommentLike.setOperation((short) 0);
                mongoTemplate.save(apCommentLike);
                // 并修改评论信息的点赞数量( + 1)
                apComment.setLikes(apComment.getLikes() + 1);
                mongoTemplate.save(apComment);

                // 计算热点评论
                if (apComment.getLikes().intValue() >= 10 && apComment.getFlag().intValue() == 0){
                    commentHotService.hotCommentExecutor(apComment);
                }

            } else {
                // 4. 如果是取消点赞操作
                // 删除点赞信息
                mongoTemplate.remove(apCommentLikeQuery,ApCommentLike.class);
                // 并修改评论信息的点赞数量( - 1) , 要判断下别减成负数
                apComment.setLikes(apComment.getLikes() < 1 ? 0 : apComment.getLikes() - 1);
                mongoTemplate.save(apComment);
            }
        } finally {
            // 解锁
            lock.unlock();
        }


        // 5. 返回结果时，需要返回点赞点赞数量  返回的key要求必须是:  likes
        Map map = new HashMap<>();
        map.put("likes",apComment.getLikes());
        return ResponseResult.okResult(map);
    }

    /**
     * 评论列表
     * @param dto
     * @return
     */
    @Override
    public ResponseResult findByArticleId(CommentDTO dto) {
        // 1. 参数校验
        // 校验文章id
        // 校验size
        if (dto.getSize() == null || dto.getSize() < 1){
            dto.setSize(10);
        }
        if (dto.getMinDate() == null){
            dto.setMinDate(new Date());
        }

        List<ApComment> apComments;
        if (dto.getIndex().intValue() == 1){ // 首次查询评论列表
            // 先查询热点评论
            Query hotQuery = Query.query(Criteria.where("articleId").is(dto.getArticleId())
                            .and("flag").is(1))
                    .with(Sort.by(Sort.Direction.DESC, "likes"));
            apComments = mongoTemplate.find(hotQuery, ApComment.class);

            Integer size = dto.getSize() - apComments.size();

            // 查询热点后，剩下size的普通评论
            Query query = Query.query(Criteria.where("articleId").is(dto.getArticleId())
                            .and("createdTime").lt(dto.getMinDate()).and("flag").is(0))
                    .with(Sort.by(Sort.Direction.DESC, "createdTime"))
                    .limit(size);
            List<ApComment> normalComments = mongoTemplate.find(query, ApComment.class);

            // 和并 普通 和 热点 评论
            apComments.addAll(normalComments);
        }else {

            // 2. 根据条件查询评论列表
            // (文章id  , 创建时间 小于最小时间 , 截取size条记录 , 创建时间降序)
            Query query = Query.query(Criteria.where("articleId").is(dto.getArticleId())
                            .and("flag").is(0)
                            .and("createdTime").lt(dto.getMinDate()))
                    .with(Sort.by(Sort.Direction.DESC, "createdTime"))
                    .limit(dto.getSize());
            // 获取所有符合条件的数据
            apComments = mongoTemplate.find(query, ApComment.class);
        }



//        Query apCommentQuery = Query.query(Criteria.where("articleId").is(dto.getArticleId()).and("createdTime").lt(dto.getMinDate()));//dto.getMinDate()
//        //分页
//        PageRequest pageable = PageRequest.of(0, dto.getSize());
//        apCommentQuery.with(pageable);
//        //排序
//        Sort sort = Sort.by(Sort.Direction.DESC, "createdTime");
//        apCommentQuery.with(sort);


        // 3. 判断当前用户是否登录
        ApUser user = AppThreadLocalUtils.getUser();
        if (user == null || CollectionUtils.isEmpty(apComments)){
            // 4. 如果未登录直接返回评论列表
            return ResponseResult.okResult(apComments);
        }

        // 5. 如果登录了 需要检查在当前评论列表中 哪些评论登陆人点赞过
        // 推荐实现:
        // 5.1 根据当前列表中评论id  和  登录人id 查询评论点赞表，得到点赞数据
        List<String> commentIds = apComments.stream().map(ApComment::getId).collect(Collectors.toList());
        // commentId  in    评论id列表   authorId = 登录人id
        Query query1 = Query.query(Criteria.where("commentId").in(commentIds).and("authorId").is(user.getId()));
        List<ApCommentLike> apCommentLikes = mongoTemplate.find(query1, ApCommentLike.class);

        // (将所有ApComment 转成 ApCommentVO , 点过赞的operation设置为0)
        ArrayList<ApCommentVo> apCommentVos = new ArrayList<>();

        // 获取点赞记录中 所有评论的id
        List<String> likeCommentIds = apCommentLikes.stream()
                .map(ApCommentLike::getCommentId)
                .distinct()
                .collect(Collectors.toList());

        // 5.2 遍历评论列表
        apComments.forEach(apComment -> {
            // 将每一个评论  ApComment 转成 ApCommentVO
            ApCommentVo apCommentVo = new ApCommentVo();
            BeanUtils.copyProperties(apComment,apCommentVo);
            // 其中  如果当前评论id在点赞记录中存在  设置operation字段为0  不存在不用做任何处理
            if (likeCommentIds.contains(apComment.getId())){
                apCommentVo.setOperation((short) 0);
            }
            apCommentVos.add(apCommentVo);
        });
        return ResponseResult.okResult(apCommentVos);
    }
}
